<?php
declare (strict_types=1);

namespace app\school\logic\school\admin;

use app\common\exception\LogicException;
use app\school\model\school\admin\SchoolDomain as SchoolDomainModel;
use think\helper\Str;
use think\Model;

class SchoolDomain extends SchoolDomainModel
{

    /**
     * 自定义列表
     *
     * @param array $map
     * @return \think\Paginator
     * @throws \think\db\exception\DbException
     */
    public function getList(array $map = [])
    {
        $buildSql = $this->field('max(`id`)')->group('mhm_id')->buildSql();

        return $this->with(['school', 'sslKey', 'sslPem'])
            ->where($map)
            ->whereRaw(sprintf('`id` IN %s', $buildSql))
            ->order('create_time', 'DESC')
            ->paginate($this->getListRows())
            ->each(function ($item) {
                // 当前生效域名
                $item->effective_domain = $this->getEffectivePcDomain($item->mhm_id);
                // 二级域名
                $item->sub_domain = $this->getPcSubDomain($item->mhm_id, $item->sub_domain_prefix);
            });
    }

    /**
     * 申请自定义域名
     *
     * @param array $data
     * @return SchoolDomain|array|\think\Model|true
     */
    public function created(array $data)
    {
        // 是否存在正在审核的申请
        $domain = $this->getInfoByMhmId(request()->mhm_id, 2);
        if (!$domain->isEmpty()) {
            throw new LogicException('正在审核中，请勿操作');
        }
        $node = $data['node'] ?? 1;
        // 数据
        $saved = [
            'node'              => $node,
            'sub_domain_prefix' => $node === 1 ? ($data['sub_domain_prefix'] ?? '') : '',
            'cname_status'      => $node === 2 ? $this->getCnameStatus($data['domain']) : 0,
            'domain'            => $node === 2 ? $data['domain'] : '',
            'is_ssl'            => $data['is_ssl'] ?? 0,
            'ssl_pem'           => $data['ssl_pem'] ?? 0,
            'ssl_key'           => $data['ssl_key'] ?? 0,
            'status'            => 2
        ];

        // 创建成功
        if (!$this->create($saved)) {
            throw new LogicException('提交失败，请重试');
        }

        return $domain;

    }

    /**
     * 域名状态
     *
     * @param $domain
     * @return int
     */
    public function getCnameStatus($domain, ?int $mhmId = 0)
    {
        $cnameStatus = 0;
        $dns         = @dns_get_record($domain, DNS_CNAME);
        if ($dns) {
            $dns         = current($dns);
            $target      = $dns['target'] ?? '';
            $mhmId       = $mhmId ?: request()->mhm_id;
            $schoolCanme = $this->getPcCname($mhmId);
            if ($target === $schoolCanme) {
                $cnameStatus = 1;
            }
        }

        return $cnameStatus;
    }

    /**
     * 根据机构id获取域名信息
     *
     * @param int $mhmId
     * @param int $status
     * @return SchoolDomain|array|Model
     */
    public function getInfoByMhmId(int $mhmId, int $status = 1)
    {
        $where = [];
        if ($status !== -1) {
            $where[] = ['status', '=', $status];
        }

        return $this->where('mhm_id', $mhmId)->where($where)->order('id', 'desc')->findOrEmpty();
    }

    /**
     * 审核
     *
     * @param int $id
     * @param int $mhmId
     * @param int $status
     * @param     $auditReason
     */
    public function doAudit(int $id, int $mhmId, int $status, $auditReason)
    {
        $domain = $this->where('id', $id)->where('mhm_id', $mhmId)->where('status', 2)->findOrEmpty();
        if ($domain->isEmpty()) {
            throw new LogicException('记录不存在或已被审核完成');
        }

        $domain->status = $status;
        if ($status === 0) {
            $domain->audit_reason = $auditReason;
        }

        // if ($status === 1) {
        //     if ($domain->node === 2) {
        //         // 是否开启了https
        //         $protocol = $domain->getAttr('is_ssl') ? 'https://' : 'http://';
        //
        //         $domain->last_domain = $protocol . $domain->domain;
        //     } else {
        //         $domain->last_domain = $this->getPcSubDomain($mhmId);
        //     }
        // }

        if (!$domain->save()) {
            throw new LogicException('操作出错，请重试');
        }
    }

    /**
     * 获取机构域名前缀
     *
     * @param      $id
     * @param bool $autoCreated
     * @return mixed|string
     */
    public function getSubDomainPrefix($id, bool $autoCreated = true)
    {
        $prefix = $this->where('mhm_id', $id)
            ->where('status', 1)
            ->where('node', 1)
            ->order('id', 'desc')
            ->value('sub_domain_prefix');
        if ($autoCreated && !$prefix) {
            return $this->createSubDomainPrefix($id);
        }

        return $prefix;
    }

    /**
     * 获取最新的域名
     *
     * @param $id
     * @return mixed
     */
    public function getLatestDomain($id)
    {
        return $this->where('mhm_id', $id)
            ->where('status', 1)
            ->where('node', 2)
            ->order('id', 'desc')
            ->value('domain');
    }

    /**
     * 生成一个不重复的二级域名前缀
     *
     * @param $id
     * @return string
     */
    public function createSubDomainPrefix($id)
    {
        $prefix  = 'app';
        $randStr = Str::random(4);
        $mid     = $id + 1000;
        $appid   = strtolower($prefix . $randStr . (string)$mid);
        if ($this->hasSubDomainPrefix($appid)) {
            return $this->createSubDomainPrefix($id);
        }

        $domain = $this->getInfoByMhmId($id, 1);
        if ($domain->isEmpty()) {
            // 记录关系
            $this->create([
                'mhm_id'            => $id,
                'node'              => 1,
                'sub_domain_prefix' => $appid,
                'status'            => 1
            ]);
        } else {
            $domain->sub_domain_prefix = $appid;
            $domain->status            = 1;
            $domain->save();
        }

        return $appid;
    }

    /**
     * 是否存在域名前缀
     *
     * @param string $prefix
     * @return bool
     */
    public function hasSubDomainPrefix(string $prefix)
    {
        return !!$this->where('sub_domain_prefix', $prefix)->value('id');
    }

    /**
     * 获取机构PC端二级域名
     *
     * @param $id
     * @return string
     */
    public function getPcSubDomain($id, ?string $prefix = null)
    {
        $subDomain = '';
        $prefix    = $prefix ?: $this->getSubDomainPrefix($id);
        $pcHost    = strtolower(config('eduline.appinfo.pc_host') ?: '');

        // 域名替换
        if (preg_match('/^(https?:\/\/)(www\.)?(.*)$/', $pcHost, $match)) {
            $ssl = config('eduline.appinfo.pc_sub_domain_ssl_node', 2);

            $protocol  = $ssl === 2 ? $match[1] : ($ssl === 1 ? 'https://' : 'http://');
            $subDomain = $protocol . $prefix . '.' . $match[3];
        }

        return $subDomain;
    }

    /**
     * 获取机构PC域名cname值
     *
     * @param $id
     * @return string
     */
    public function getPcCname($id)
    {
        $cname   = '';
        $prefix  = $this->getSubDomainPrefix($id);
        $pcCname = strtolower(config('eduline.appinfo.pc_cname') ?: '');

        // 如果不指定单独的cname域名，则以主站域名计算
        if (!$pcCname) {
            $pcCname = str_replace(['http://', 'https://'], '', strtolower(config('eduline.appinfo.pc_host') ?: ''));
        }

        // 域名替换
        if (preg_match('/^(www\.)?(.*)$/', $pcCname, $match)) {
            $cname = $prefix . '.pc-cname.' . $match[2];
        }

        return $cname;
    }

    /**
     * 获取机构PC域名后半部分
     *
     * @return string
     */
    public function getPcSubDomainSuffix()
    {
        $suffix = '';
        $pcHost = strtolower(config('eduline.appinfo.pc_host') ?: '');
        if (preg_match('/^(https?:\/\/)(www\.)?(.*)$/', $pcHost, $match)) {
            $suffix = '.' . $match['3'];
        }

        return $suffix;
    }

    /**
     * 获取当前生效的机构域名
     *
     * @param int $mhmId
     * @return string
     */
    public function getEffectivePcDomain(int $mhmId)
    {
        // 机构生效的二级域名
        $domain = $this->getPcSubDomain($mhmId);
        // 获取已经通过的域名
        $info = $this->getInfoByMhmId($mhmId, 1);
        // 是否审核通过
        if ($info->status === 1) {
            // 域名模式: 自定义域名
            if ($info->node === 2) {
                // 域名解析正常
                if ($info->cname_status === 1) {
                    // 是否开启了https
                    $protocol = $info->getAttr('is_ssl') ? 'https://' : 'http://';
                    $domain   = $protocol . $info->getAttr('domain');
                }
            }
        }

        return $domain;
    }

    /**
     * 根据二级域名前缀获取机构id
     *
     * @param string $subDomainPrefix
     * @return int
     */
    public function getMhmIdBySubDomainPrefix(string $subDomainPrefix, int $status = -1)
    {
        $where = [];
        if ($status !== -1) {
            $where[] = ['status', '=', $status];
        }

        return (int)$this->where('sub_domain_prefix', $subDomainPrefix)
            ->where($where)
            ->order('id', 'desc')
            ->value('mhm_id');
    }

    /**
     * 获取匹配的域名,返回机构id
     *
     * @param string $subDomainPrefix
     * @param int    $status
     * @return int
     */
    public function getMatchMhmId(string $subDomainPrefix)
    {
        // 匹配当前通过的域名前缀
        $mhmId = $this->getMhmIdBySubDomainPrefix($subDomainPrefix, 1);

        return $mhmId;
    }
}